use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    response::Json,
};
use serde::Deserialize;
use crate::models::{
    CreateLineageRequest, UpdateLineageRequest, ProcessLineageSuggestionsRequest,
    DataLineageWithDetails, LineageSuggestionWithDetails, LineageGraph, LineageStats,
    DataItemWithFullLineage, LineageSuggestionResponse
};
use crate::error::AppError;
use crate::utils::AuthenticatedUser;

#[derive(Debug, Deserialize)]
pub struct LineageQueryParams {
    pub child_id: Option<i64>,
    pub parent_id: Option<i64>,
    pub relationship_type: Option<String>,
    pub detection_method: Option<String>,
    pub limit: Option<i64>,
    pub offset: Option<i64>,
}

#[derive(Debug, Deserialize)]
pub struct LineageGraphQuery {
    pub center_item_id: Option<i64>,
    pub max_depth: Option<i32>,
    pub user_id: Option<i64>,
}

#[derive(Debug, Deserialize)]
pub struct LineageSuggestionsQuery {
    pub child_id: Option<i64>,
    pub status: Option<String>,
    pub limit: Option<i64>,
}

// Get lineage relationships with filtering
pub async fn get_lineage_relationships(
    Query(_params): Query<LineageQueryParams>,
    AuthenticatedUser(_user): AuthenticatedUser,
    State(_state): State<crate::AppState>,
) -> Result<Json<Vec<DataLineageWithDetails>>, AppError> {
    // TODO: Implement with SeaORM - return empty for now
    Ok(Json(vec![]))
}

// Get full lineage information for a specific data item
pub async fn get_data_item_lineage(
    Path(item_id): Path<i64>,
    AuthenticatedUser(user): AuthenticatedUser,
    State(state): State<crate::AppState>,
) -> Result<Json<DataItemWithFullLineage>, AppError> {
    let lineage = state.lineage_service.get_lineage_for_item(item_id).await
        .map_err(|e| AppError::Internal(format!("Failed to get lineage for item: {}", e)))?;

    // Verify user has access to this item
    if lineage.data_item.user_id != user.id && !lineage.data_item.is_public {
        return Err(AppError::Forbidden("You don't have access to this item".to_string()));
    }

    Ok(Json(lineage))
}

// Create a new lineage relationship
pub async fn create_lineage_relationship(
    AuthenticatedUser(user): AuthenticatedUser,
    State(state): State<crate::AppState>,
    Json(request): Json<CreateLineageRequest>,
) -> Result<Json<DataLineageWithDetails>, AppError> {
    // Verify user has access to both items
    let child_item = state.data_service.get_data_item(request.child_id, user.id).await
        .map_err(|e| AppError::Internal(format!("Failed to get child item: {}", e)))?;

    let parent_item = state.data_service.get_data_item(request.parent_id, user.id).await
        .map_err(|e| AppError::Internal(format!("Failed to get parent item: {}", e)))?;

    if child_item.is_none() || parent_item.is_none() {
        return Err(AppError::NotFound("One or both data items not found".to_string()));
    }

    let new_lineage = crate::models::NewDataLineage {
        child_id: request.child_id,
        parent_id: request.parent_id,
        relationship_type: request.relationship_type,
        confidence: 1.0, // Manual relationships have full confidence
        detection_method: "manual".to_string(),
        description: request.description,
        created_by: user.id,
    };

    let lineage = state.lineage_service.create_lineage(new_lineage).await
        .map_err(|e| AppError::Internal(format!("Failed to create lineage: {}", e)))?;

    // Get full details
    let lineage_with_details = state.lineage_service.get_lineage_by_id(lineage.id).await
        .map_err(|e| AppError::Internal(format!("Failed to get lineage details: {}", e)))?
        .ok_or_else(|| AppError::Internal("Failed to retrieve created lineage".to_string()))?;

    Ok(Json(lineage_with_details))
}

// Update a lineage relationship
pub async fn update_lineage_relationship(
    Path(lineage_id): Path<i64>,
    AuthenticatedUser(user): AuthenticatedUser,
    State(state): State<crate::AppState>,
    Json(request): Json<UpdateLineageRequest>,
) -> Result<Json<DataLineageWithDetails>, AppError> {
    // Verify user owns this lineage relationship
    let existing = state.lineage_service.get_lineage_by_id(lineage_id).await
        .map_err(|e| AppError::Internal(format!("Failed to get existing lineage: {}", e)))?
        .ok_or_else(|| AppError::NotFound("Lineage relationship not found".to_string()))?;

    if existing.created_by != user.id && !user.is_admin {
        return Err(AppError::Forbidden("You can only update your own lineage relationships".to_string()));
    }

    // Update the lineage relationship
    sqlx::query!(
        r#"
        UPDATE data_lineage
        SET relationship_type = COALESCE(?, relationship_type),
            description = COALESCE(?, description),
            updated_at = CURRENT_TIMESTAMP
        WHERE id = ?
        "#,
        request.relationship_type,
        request.description,
        lineage_id
    )
    .execute(&state.lineage_service.pool)
    .await
    .map_err(|e| AppError::Internal(format!("Failed to update lineage: {}", e)))?;

    // Return updated lineage
    let updated = state.lineage_service.get_lineage_by_id(lineage_id).await
        .map_err(|e| AppError::Internal(format!("Failed to get updated lineage: {}", e)))?
        .ok_or_else(|| AppError::Internal("Failed to retrieve updated lineage".to_string()))?;

    Ok(Json(updated))
}

// Delete a lineage relationship
pub async fn delete_lineage_relationship(
    Path(lineage_id): Path<i64>,
    AuthenticatedUser(user): AuthenticatedUser,
    State(state): State<crate::AppState>,
) -> Result<StatusCode, AppError> {
    // Verify user owns this lineage relationship
    let existing = state.lineage_service.get_lineage_by_id(lineage_id).await
        .map_err(|e| AppError::Internal(format!("Failed to get existing lineage: {}", e)))?
        .ok_or_else(|| AppError::NotFound("Lineage relationship not found".to_string()))?;

    if existing.created_by != user.id && !user.is_admin {
        return Err(AppError::Forbidden("You can only delete your own lineage relationships".to_string()));
    }

    sqlx::query!("DELETE FROM data_lineage WHERE id = ?", lineage_id)
        .execute(&state.lineage_service.pool)
        .await
        .map_err(|e| AppError::Internal(format!("Failed to delete lineage: {}", e)))?;

    Ok(StatusCode::NO_CONTENT)
}

// Generate lineage graph for visualization
pub async fn get_lineage_graph(
    Query(params): Query<LineageGraphQuery>,
    AuthenticatedUser(user): AuthenticatedUser,
    State(state): State<crate::AppState>,
) -> Result<Json<LineageGraph>, AppError> {
    let max_depth = params.max_depth.unwrap_or(3);
    let center_item_id = params.center_item_id;

    let graph = state.lineage_service.generate_lineage_graph(center_item_id, max_depth).await
        .map_err(|e| AppError::Internal(format!("Failed to generate lineage graph: {}", e)))?;

    Ok(Json(graph))
}

// Get lineage statistics
pub async fn get_lineage_statistics(
    AuthenticatedUser(user): AuthenticatedUser,
    State(state): State<crate::AppState>,
) -> Result<Json<LineageStats>, AppError> {
    let stats = state.lineage_service.get_lineage_stats(Some(user.id)).await
        .map_err(|e| AppError::Internal(format!("Failed to get lineage stats: {}", e)))?;

    Ok(Json(stats))
}

// Get lineage suggestions
pub async fn get_lineage_suggestions(
    Query(params): Query<LineageSuggestionsQuery>,
    AuthenticatedUser(user): AuthenticatedUser,
    State(state): State<crate::AppState>,
) -> Result<Json<Vec<LineageSuggestionWithDetails>>, AppError> {
    let mut query = "
        SELECT
            ls.id, ls.child_id, ls.suggested_parent_id, ls.confidence_score,
            ls.suggestion_reason, ls.detection_method, ls.status,
            ls.created_at, ls.reviewed_at, ls.reviewed_by,
            child.name as child_name, child.user_id as child_user_id,
            parent.name as parent_name, parent.user_id as parent_user_id,
            reviewer.email as reviewed_by_email
        FROM lineage_suggestions ls
        JOIN data_items child ON ls.child_id = child.id
        JOIN data_items parent ON ls.suggested_parent_id = parent.id
        LEFT JOIN users reviewer ON ls.reviewed_by = reviewer.id
        WHERE child.user_id = ? AND ls.status = 'pending'
        ORDER BY ls.confidence_score DESC
    ".to_string();

    let mut limit = params.limit.unwrap_or(20);
    if limit > 100 { limit = 100; } // Cap at 100 for performance

    query.push_str(&format!(" LIMIT {}", limit));

    let suggestions = sqlx::query_as!(
        LineageSuggestionWithDetails,
        r#"
        SELECT
            ls.id, ls.child_id, ls.suggested_parent_id, ls.confidence_score,
            ls.suggestion_reason, ls.detection_method, ls.status,
            ls.created_at, ls.reviewed_at, ls.reviewed_by,
            child.name as "child_name: String", child.user_id as child_user_id,
            parent.name as "parent_name: String", parent.user_id as parent_user_id,
            reviewer.email as reviewed_by_email
        FROM lineage_suggestions ls
        JOIN data_items child ON ls.child_id = child.id
        JOIN data_items parent ON ls.suggested_parent_id = parent.id
        LEFT JOIN users reviewer ON ls.reviewed_by = reviewer.id
        WHERE child.user_id = ? AND ls.status = 'pending'
        ORDER BY ls.confidence_score DESC
        LIMIT 20
        "#,
        user.id
    )
    .fetch_all(&state.lineage_service.pool)
    .await
    .map_err(|e| AppError::Internal(format!("Failed to fetch lineage suggestions: {}", e)))?;

    // Apply additional filtering if needed
    let filtered_suggestions = suggestions.into_iter()
        .filter(|suggestion| {
            if let Some(child_id) = params.child_id {
                if suggestion.suggestion.child_id != child_id { return false; }
            }
            if let Some(ref status) = params.status {
                if suggestion.suggestion.status != *status { return false; }
            }
            true
        })
        .collect();

    Ok(Json(filtered_suggestions))
}

// Process a lineage suggestion (accept/reject)
pub async fn process_lineage_suggestion(
    AuthenticatedUser(user): AuthenticatedUser,
    State(state): State<crate::AppState>,
    Json(request): Json<ProcessLineageSuggestionsRequest>,
) -> Result<Json<LineageSuggestionResponse>, AppError> {
    // Verify the suggestion belongs to the user
    let suggestion = state.lineage_service.get_suggestion_by_id(request.suggestion_id).await
        .map_err(|e| AppError::Internal(format!("Failed to get suggestion: {}", e)))?
        .ok_or_else(|| AppError::NotFound("Lineage suggestion not found".to_string()))?;

    if suggestion.child_user_id != user.id {
        return Err(AppError::Forbidden("This suggestion doesn't belong to you".to_string()));
    }

    // Process the suggestion
    state.lineage_service.process_suggestion(
        request.suggestion_id,
        &request.action,
        user.id,
        request.relationship_type,
        request.description,
    ).await
    .map_err(|e| AppError::Internal(format!("Failed to process suggestion: {}", e)))?;

    // Get similar relationships for context
    let similar_relationships = sqlx::query_as!(
        DataLineageWithDetails,
        r#"
        SELECT
            dl.id, dl.child_id, dl.parent_id, dl.relationship_type, dl.confidence,
            dl.detection_method, dl.description, dl.created_by, dl.created_at, dl.updated_at,
            child.name as "child_name: String", child.file_path as "child_path: String",
            child.file_size as child_size, child.user_id as child_user_id, child.is_public as child_public,
            parent.name as "parent_name: String", parent.file_path as "parent_path: String",
            parent.file_size as parent_size, parent.user_id as parent_user_id, parent.is_public as parent_public,
            creator.email as "created_by_email: String"
        FROM data_lineage dl
        JOIN data_items child ON dl.child_id = child.id
        JOIN data_items parent ON dl.parent_id = parent.id
        JOIN users creator ON dl.created_by = creator.id
        WHERE (dl.parent_id = ? OR dl.child_id = ?) AND dl.id != ?
        ORDER BY dl.confidence DESC
        LIMIT 5
        "#,
        suggestion.suggested_parent_id,
        suggestion.child_id,
        suggestion.id
    )
    .fetch_all(&state.lineage_service.pool)
    .await
    .map_err(|e| AppError::Internal(format!("Failed to fetch similar relationships: {}", e)))?;

    Ok(Json(LineageSuggestionResponse {
        suggestion,
        similar_relationships: similar_relationships,
    }))
}

// Trigger auto-detection for a specific item
pub async fn trigger_lineage_detection(
    Path(item_id): Path<i64>,
    AuthenticatedUser(user): AuthenticatedUser,
    State(state): State<crate::AppState>,
) -> Result<Json<Vec<crate::models::NewLineageSuggestion>>, AppError> {
    // Verify user has access to this item
    let item = state.data_service.get_data_item(item_id, user.id).await
        .map_err(|e| AppError::Internal(format!("Failed to get data item: {}", e)))?;

    if item.is_none() {
        return Err(AppError::NotFound("Data item not found".to_string()));
    }

    let suggestions = state.lineage_service.auto_detect_lineage(item_id).await
        .map_err(|e| AppError::Internal(format!("Failed to auto-detect lineage: {}", e)))?;

    Ok(Json(suggestions))
}

// Get lineage paths between two items
pub async fn get_lineage_paths(
    Path((from_id, to_id)): Path<(i64, i64)>,
    AuthenticatedUser(user): AuthenticatedUser,
    State(state): State<crate::AppState>,
) -> Result<Json<Vec<crate::models::LineagePath>>, AppError> {
    // Verify user has access to both items
    let from_item = state.data_service.get_data_item(from_id, user.id).await
        .map_err(|e| AppError::Internal(format!("Failed to get source item: {}", e)))?;

    let to_item = state.data_service.get_data_item(to_id, user.id).await
        .map_err(|e| AppError::Internal(format!("Failed to get target item: {}", e)))?;

    if from_item.is_none() || to_item.is_none() {
        return Err(AppError::NotFound("One or both data items not found".to_string()));
    }

    // Simplified path tracing - just return direct relationships
    let paths = sqlx::query!(
        r#"
        SELECT dl.*,
               child.name as child_name,
               parent.name as parent_name,
               dl.created_at as relationship_created_at
        FROM data_lineage dl
        JOIN data_items child ON dl.child_id = child.id
        JOIN data_items parent ON dl.parent_id = parent.id
        WHERE (dl.child_id = ? OR dl.parent_id = ?)
        ORDER BY dl.created_at DESC
        LIMIT 20
        "#,
        from_id,
        from_id
    )
    .fetch_all(&state.lineage_service.pool)
    .await
    .map_err(|e| AppError::Internal(format!("Failed to find lineage paths: {}", e)))?;

    // Return simplified result
    let result_paths = vec![crate::models::LineagePath {
        path: vec![],
        relationships: vec![],
        path_length: paths.len() as i32,
        total_size: 0,
    }];

    Ok(Json(result_paths))
}